package main

import (
	"encoding/binary"
	"encoding/hex"
	"fmt"
	"strings"
	"sync"
	"time"

	"go.bug.st/serial"
	"go.bug.st/serial/enumerator"
)

// SerialConfig 串口配置
type SerialConfig struct {
	PortName    string  `json:"portName"`
	BaudRate    int     `json:"baudRate"`
	DataBits    int     `json:"dataBits"`
	Parity      string  `json:"parity"`
	StopBits    float32 `json:"stopBits"`
	FlowControl string  `json:"flowControl"`
}

// SerialMessage 串口消息
type SerialMessage struct {
	Data      string `json:"data"`
	Direction string `json:"direction"` // "send" 或 "receive"
	Timestamp string `json:"timestamp"`
	Format    string `json:"format"` // "hex" 或 "ascii"
}

// SerialManager 串口管理器
type SerialManager struct {
	port         serial.Port
	isOpen       bool
	config       SerialConfig
	messages     []SerialMessage
	readBuffer   []byte
	mutex        sync.Mutex
	stopReading  chan bool
	messagesChan chan SerialMessage
}

// NewSerialManager 创建新的串口管理器
func NewSerialManager() *SerialManager {
	return &SerialManager{
		isOpen:       false,
		readBuffer:   make([]byte, 1024),
		stopReading:  make(chan bool),
		messagesChan: make(chan SerialMessage, 100),
		messages:     []SerialMessage{},
		config: SerialConfig{
			BaudRate:    9600,
			DataBits:    8,
			Parity:      "N",
			StopBits:    1,
			FlowControl: "none",
		},
	}
}

// GetPortsList 获取可用串口列表
func (sm *SerialManager) GetPortsList() ([]string, error) {
	ports, err := enumerator.GetDetailedPortsList()
	if err != nil {
		return nil, err
	}

	var result []string
	for _, port := range ports {
		name := port.Name
		if port.IsUSB {
			name = fmt.Sprintf("%s [%s %s]", port.Name, port.VID, port.PID)
		}
		result = append(result, name)
	}
	return result, nil
}

// OpenPort 打开串口
func (sm *SerialManager) OpenPort(config SerialConfig) error {
	sm.mutex.Lock()
	defer sm.mutex.Unlock()

	if sm.isOpen {
		return fmt.Errorf("串口已经打开")
	}

	// 解析校验位
	var parity serial.Parity
	switch strings.ToUpper(config.Parity) {
	case "N":
		parity = serial.NoParity
	case "O":
		parity = serial.OddParity
	case "E":
		parity = serial.EvenParity
	case "M":
		parity = serial.MarkParity
	case "S":
		parity = serial.SpaceParity
	default:
		parity = serial.NoParity
	}

	// 解析停止位
	var stopBits serial.StopBits
	switch config.StopBits {
	case 1:
		stopBits = serial.OneStopBit
	case 1.5:
		stopBits = serial.OnePointFiveStopBits
	case 2:
		stopBits = serial.TwoStopBits
	default:
		stopBits = serial.OneStopBit
	}

	// 设置串口模式
	mode := &serial.Mode{
		BaudRate: config.BaudRate,
		DataBits: config.DataBits,
		Parity:   parity,
		StopBits: stopBits,
	}

	// 打开串口
	port, err := serial.Open(config.PortName, mode)
	if err != nil {
		return err
	}

	sm.port = port
	sm.isOpen = true
	sm.config = config

	// 启动读取协程
	go sm.readLoop()

	return nil
}

// ClosePort 关闭串口
func (sm *SerialManager) ClosePort() error {
	sm.mutex.Lock()
	defer sm.mutex.Unlock()

	if !sm.isOpen {
		return fmt.Errorf("串口未打开")
	}

	// 停止读取协程
	sm.stopReading <- true

	// 关闭串口
	err := sm.port.Close()
	if err != nil {
		return err
	}

	sm.isOpen = false
	return nil
}

// IsPortOpen 检查串口是否打开
func (sm *SerialManager) IsPortOpen() bool {
	sm.mutex.Lock()
	defer sm.mutex.Unlock()
	return sm.isOpen
}

// GetCurrentConfig 获取当前配置
func (sm *SerialManager) GetCurrentConfig() SerialConfig {
	sm.mutex.Lock()
	defer sm.mutex.Unlock()
	return sm.config
}

// SendData 发送数据
func (sm *SerialManager) SendData(data string, format string) error {
	sm.mutex.Lock()
	defer sm.mutex.Unlock()

	if !sm.isOpen {
		return fmt.Errorf("串口未打开")
	}

	var bytes []byte
	var err error

	// 根据格式转换数据
	if format == "hex" {
		// 移除所有空格
		data = strings.ReplaceAll(data, " ", "")
		bytes, err = hex.DecodeString(data)
		if err != nil {
			return fmt.Errorf("无效的十六进制数据: %v", err)
		}
	} else {
		// ASCII格式
		bytes = []byte(data)
	}

	// 发送数据
	_, err = sm.port.Write(bytes)
	if err != nil {
		return err
	}

	// 记录发送的消息
	message := SerialMessage{
		Data:      data,
		Direction: "send",
		Timestamp: time.Now().Format("15:04:05.000"),
		Format:    format,
	}
	sm.messages = append(sm.messages, message)
	sm.messagesChan <- message

	return nil
}

// GetMessages 获取所有消息
func (sm *SerialManager) GetMessages() []SerialMessage {
	sm.mutex.Lock()
	defer sm.mutex.Unlock()
	return sm.messages
}

// ClearMessages 清除所有消息
func (sm *SerialManager) ClearMessages() {
	sm.mutex.Lock()
	defer sm.mutex.Unlock()
	sm.messages = []SerialMessage{}
}

// readLoop 持续读取串口数据
func (sm *SerialManager) readLoop() {
	for {
		select {
		case <-sm.stopReading:
			return
		default:
			sm.mutex.Lock()
			if !sm.isOpen {
				sm.mutex.Unlock()
				return
			}

			// 设置读取超时
			err := sm.port.SetReadTimeout(100 * time.Millisecond)
			if err != nil {
				sm.mutex.Unlock()
				continue
			}

			// 读取数据
			n, err := sm.port.Read(sm.readBuffer)
			if err != nil {
				sm.mutex.Unlock()
				continue
			}

			if n > 0 {
				data := make([]byte, n)
				copy(data, sm.readBuffer[:n])

				// 创建接收消息
				var dataStr string
				dataStr = hex.EncodeToString(data)

				message := SerialMessage{
					Data:      dataStr,
					Direction: "receive",
					Timestamp: time.Now().Format("15:04:05.000"),
					Format:    "hex",
				}

				sm.messages = append(sm.messages, message)
				sm.messagesChan <- message
			}
			sm.mutex.Unlock()
		}
	}
}

// CalculateModbusCRC 计算Modbus CRC校验
func CalculateModbusCRC(data []byte) uint16 {
	crc := uint16(0xFFFF)
	for _, b := range data {
		crc ^= uint16(b)
		for i := 0; i < 8; i++ {
			if (crc & 0x0001) != 0 {
				crc = (crc >> 1) ^ 0xA001
			} else {
				crc >>= 1
			}
		}
	}
	return crc
}

// AppendModbusCRC 添加Modbus CRC校验
func AppendModbusCRC(data []byte) []byte {
	crc := CalculateModbusCRC(data)
	result := make([]byte, len(data)+2)
	copy(result, data)

	// 低字节在前，高字节在后
	result[len(data)] = byte(crc & 0xFF)
	result[len(data)+1] = byte(crc >> 8)

	return result
}

// VerifyModbusCRC 验证Modbus CRC校验
func VerifyModbusCRC(data []byte) bool {
	if len(data) < 2 {
		return false
	}

	message := data[:len(data)-2]
	receivedCRC := binary.LittleEndian.Uint16(data[len(data)-2:])
	calculatedCRC := CalculateModbusCRC(message)

	return receivedCRC == calculatedCRC
}

// ComTxRx 发送数据并等待接收响应
// txbuf: 发送缓冲区
// txlen: 发送数据长度
// rxbuf: 接收缓冲区
// rxlen: 期望接收的数据长度
// timeout: 接收超时时间
// 返回: 实际接收到的数据长度, 错误信息
func (sm *SerialManager) ComTxRx(txbuf []byte, txlen int, rxbuf []byte, rxlen int, timeout time.Duration) (int, error) {
	sm.mutex.Lock()
	defer sm.mutex.Unlock()

	// 检查串口是否打开
	if !sm.isOpen {
		return 0, fmt.Errorf("串口未打开")
	}

	// 检查参数有效性
	if txlen > len(txbuf) {
		return 0, fmt.Errorf("发送长度超出缓冲区大小")
	}
	if rxlen > len(rxbuf) {
		return 0, fmt.Errorf("接收长度超出缓冲区大小")
	}

	// 清空接收缓冲区
	err := sm.port.ResetInputBuffer()
	if err != nil {
		return 0, fmt.Errorf("清空接收缓冲区失败: %v", err)
	}

	// 发送数据
	_, err = sm.port.Write(txbuf[:txlen])
	if err != nil {
		return 0, fmt.Errorf("发送数据失败: %v", err)
	}

	// 记录发送的消息
	message := SerialMessage{
		Data:      hex.EncodeToString(txbuf[:txlen]),
		Direction: "send",
		Timestamp: time.Now().Format("15:04:05.000"),
		Format:    "hex",
	}
	sm.messages = append(sm.messages, message)
	sm.messagesChan <- message

	// 临时解锁互斥锁，以便其他协程可以访问串口
	sm.mutex.Unlock()

	// 设置接收超时
	err = sm.port.SetReadTimeout(timeout)
	if err != nil {
		sm.mutex.Lock()
		return 0, fmt.Errorf("设置读取超时失败: %v", err)
	}

	// 创建接收缓冲区
	tempBuf := make([]byte, rxlen)
	totalRead := 0
	startTime := time.Now()

	// 读取数据直到接收到足够的数据或超时
	for totalRead < rxlen && time.Since(startTime) < timeout {
		n, err := sm.port.Read(tempBuf[totalRead:])
		if err != nil {
			sm.mutex.Lock()
			return totalRead, fmt.Errorf("读取数据失败: %v", err)
		}
		if n > 0 {
			totalRead += n
		}
		// 如果没有读到数据，短暂休眠避免CPU占用过高
		if n == 0 {
			time.Sleep(5 * time.Millisecond)
		}
	}

	// 重新获取互斥锁
	sm.mutex.Lock()

	// 检查是否超时
	if totalRead < rxlen && time.Since(startTime) >= timeout {
		// 即使超时，也返回已读取的数据
		copy(rxbuf, tempBuf[:totalRead])

		// 记录接收的消息
		if totalRead > 0 {
			message := SerialMessage{
				Data:      hex.EncodeToString(tempBuf[:totalRead]),
				Direction: "receive",
				Timestamp: time.Now().Format("15:04:05.000"),
				Format:    "hex",
			}
			sm.messages = append(sm.messages, message)
			sm.messagesChan <- message
		}

		return totalRead, fmt.Errorf("接收超时，已接收 %d/%d 字节", totalRead, rxlen)
	}

	// 复制数据到接收缓冲区
	copy(rxbuf, tempBuf[:totalRead])

	// 记录接收的消息
	message = SerialMessage{
		Data:      hex.EncodeToString(tempBuf[:totalRead]),
		Direction: "receive",
		Timestamp: time.Now().Format("15:04:05.000"),
		Format:    "hex",
	}
	sm.messages = append(sm.messages, message)
	sm.messagesChan <- message

	return totalRead, nil
}
